#include "stdafx.h"
#include "problem_solver_core.h"
#include "problem.h"
#include "Problem Form.h"
#include "Create Problem Form.h"
#include "tag_info.h"

namespace SimpleGUI
{
	// Constructor and Destructor

	template <class T, class U> Problem<T, U>::Problem(nnse::problem<T, U>^ p)
	: parent(p)
	{
		InitializeComponent();
		load_toolTip->SetToolTip(load_button, "Load a set of examples from a file.");
		save_toolTip->SetToolTip(save_button, "Save a set of examples to a file.");
		create_toolTip->SetToolTip(create_button, "Create a new set of examples.");
		prev_toolTip->SetToolTip(prev_button, "View the previous example in the set.");
		next_toolTip->SetToolTip(next_button, "View the next example in the set.");
		training_toolTip->SetToolTip(training_radioButton, "View the examples that will be used to train the Neural Network.");
		testing_toolTip->SetToolTip(testing_radioButton, "View the examples that will be used to test the Neural Network.");
		input_toolTip->SetToolTip(input_radioButton, "View the examples that will be used as inputs to the Neural Network.");
		target_toolTip->SetToolTip(target_radioButton, "View the examples that will be used as targets for the Neural Network.");
		create_solver_toolTip->SetToolTip(create_solver_button, "Create the Neural Network.");
		comment_toolTip->SetToolTip(comment_textBox, "A comment for the current vector.");
		file_textBox->Enabled=false;
		current_training_example_textBox->Enabled=false;
		current_testing_example_textBox->Enabled=false;
		set_file_filter();
		update_form("Ready", 0, 0, 0);
		this->Show();
	};

	template <class T, class U> Problem<T, U>::~Problem()
	{
		if (components)
		{
			delete components;
		}
	};

	// GUI Functions

	template <class T, class U> System::Void Problem<T, U>::load_button_Click(System::Object^ sender, System::EventArgs^ e)
	{
		if (load_openFileDialog->ShowDialog()==System::Windows::Forms::DialogResult::OK)
		{
			update_form("Loading...", 0, 0, 0);
			parent->load(load_openFileDialog->FileName);
			add_grid();
			show_vector();
			update_form("Ready", 0, 0, 0);
		}
	};

	template <class T, class U> System::Void Problem<T, U>::save_button_Click(System::Object^ sender, System::EventArgs^ e)
	{
		if (save_saveFileDialog->ShowDialog()==System::Windows::Forms::DialogResult::OK)
		{
			update_form("Saving...", 0, 0, 0);
			parent->save(save_saveFileDialog->FileName);
			add_grid();
			show_vector();
			update_form("Ready", 0, 0, 0);
		}
	};

	template <class T, class U> System::Void Problem<T, U>::create_button_Click(System::Object^ sender, System::EventArgs^ e)
	{
		SimpleGUI::CreateProblemForm<T, U>^ create_problem_form=gcnew SimpleGUI::CreateProblemForm<T, U>(parent);
		if (create_problem_form->ShowDialog()==System::Windows::Forms::DialogResult::OK)
		{
			update_form("Creating...", 0, 0, 0);
			parent->create();
			add_grid();
			show_vector();
			update_form("Ready", 0, 0, 0);
		}
	};

	template <class T, class U> System::Void Problem<T, U>::prev_button_Click(System::Object^ sender, System::EventArgs^ e)
	{
		update_form("Getting previous example...", 0, 0, 0);
		unsigned int current_example=parent->get_current_example();
		if (current_example==0)
		{
			parent->put_current_example(parent->get_number_of_examples()-1);
		}
		else
		{
			parent->put_current_example(current_example-1);
		}
		show_vector();
		update_form("Ready", 0, 0, 0);
	};

	template <class T, class U> System::Void Problem<T, U>::next_button_Click(System::Object^ sender, System::EventArgs^ e)
	{
		update_form("Getting next example...", 0, 0, 0);
		unsigned int current_example=parent->get_current_example();
		if (current_example==parent->get_number_of_examples()-1)
		{
			parent->put_current_example(0);
		}
		else
		{
			parent->put_current_example(current_example+1);
		}
		show_vector();
		update_form("Ready", 0, 0, 0);
	};

	template <class T, class U> System::Void Problem<T, U>::training_radioButton_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
	{
		if (training_radioButton->Checked && !(testing_radioButton->Checked))
		{
			parent->put_training_flag();
			if (parent->training_input_done && parent->training_target_done)
			{
				add_grid();
				show_vector();
			}
		}
	};

	template <class T, class U> System::Void Problem<T, U>::testing_radioButton_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
	{
		if (!(training_radioButton->Checked) && testing_radioButton->Checked)
		{
			parent->put_testing_flag();
			if (parent->testing_input_done && parent->testing_target_done)
			{
				add_grid();
				show_vector();
			}
		}
	};

	template <class T, class U> System::Void Problem<T, U>::input_radioButton_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
	{
		if (input_radioButton->Checked && !(target_radioButton->Checked))
		{
			parent->put_input_flag();
			if (parent->training_input_done && parent->testing_input_done)
			{
				add_grid();
				show_vector();
			}
		}
	};

	template <class T, class U> System::Void Problem<T, U>::target_radioButton_CheckedChanged(System::Object^ sender, System::EventArgs^ e)
	{
		if (!(input_radioButton->Checked) && target_radioButton->Checked)
		{
			parent->put_target_flag();
			if (parent->training_target_done && parent->testing_target_done)
			{
				add_grid();
				show_vector();
			}
		}
	};

	template <class T, class U> System::Void Problem<T, U>::create_solver_button_Click(System::Object^  sender, System::EventArgs^  e)
	{
		parent->put_solver();
	};

	template <class T, class U> System::Void Problem<T, U>::comment_textBox_TextChanged(System::Object^ sender, System::EventArgs^ e)
	{
		parent->put_comment(comment_textBox->Text);
	};

	template <class T, class U> System::Void Problem<T, U>::grid_Click(System::Object^ sender, System::EventArgs^ e)
	{
		System::Windows::Forms::Label^ label=dynamic_cast<System::Windows::Forms::Label^>(sender);
		SimpleGUI::tag_info^ tag=dynamic_cast<SimpleGUI::tag_info^>(label->Tag);
		parent->put_value(tag->get_linear_index(), !(parent->get_value(tag->get_linear_index())));
		show_vector();
	};

	template <class T, class U> System::Void Problem<T, U>::update_form(System::String^ progress_text, unsigned int progress_min, unsigned int progress_val, unsigned int progress_max)
	{
		training_radioButton->Enabled=false;
		testing_radioButton->Enabled=false;
		input_radioButton->Enabled=false;
		target_radioButton->Enabled=false;
		create_solver_button->Enabled=false;
		if (parent->training_input_done && parent->training_target_done)
		{
			training_radioButton->Enabled=true;
		}
		if (parent->testing_input_done && parent->testing_target_done)
		{
			testing_radioButton->Enabled=true;
		}
		if (parent->training_input_done && parent->testing_input_done)
		{
			input_radioButton->Enabled=true;
		}
		if (parent->training_target_done && parent->testing_target_done)
		{
			target_radioButton->Enabled=true;
		}
		if (parent->training_input_done && parent->training_target_done && parent->testing_input_done && parent->testing_target_done)
		{
			create_solver_button->Enabled=true;
		}
		file_textBox->Text=parent->get_file_name();
		if (training_radioButton->Checked!=parent->get_training_flag())
		{
			training_radioButton->Checked=parent->get_training_flag();
		}
		if (testing_radioButton->Checked!=parent->get_testing_flag())
		{
			testing_radioButton->Checked=parent->get_testing_flag();
		}
		if (input_radioButton->Checked!=parent->get_input_flag())
		{
			input_radioButton->Checked=parent->get_input_flag();
		}
		if (target_radioButton->Checked!=parent->get_target_flag())
		{
			target_radioButton->Checked=parent->get_target_flag();
		}
		current_training_example_textBox->Text=(parent->get_current_training_example() + 1).ToString();
		current_testing_example_textBox->Text=(parent->get_current_testing_example() + 1).ToString();
		status_label->Text=progress_text;
		status_progressBar->Minimum=progress_min;
		status_progressBar->Value=progress_val;
		status_progressBar->Maximum=progress_max;
		this->Refresh();
	}

	template <class T, class U> System::Void Problem<T, U>::add_grid()
	{
		remove_grid();
		unsigned int x_offset=comment_textBox->Location.X;
		unsigned int y_offset=comment_textBox->Location.Y + comment_textBox->Size.Height;
		unsigned int x_size=20;
		unsigned int y_size=20;
		System::EventHandler^% grid_callback=gcnew System::EventHandler(this, &Problem::grid_Click);
		this->SuspendLayout();
		grid=gcnew array<System::Windows::Forms::Label^>(parent->get_number_of_elements());
		for(unsigned int el=0; el<parent->get_number_of_elements(); el++)
		{
			grid[el]=gcnew System::Windows::Forms::Label();
			tag_info^ tag=gcnew tag_info(el, parent->get_wrap_element());
			grid[el]->Tag=tag;
			grid[el]->Location=System::Drawing::Point(x_offset + (tag->get_column_index() * x_size), y_offset + (tag->get_row_index() * y_size));
			grid[el]->Size=System::Drawing::Size(x_size, y_size);
			grid[el]->BackColor=System::Drawing::SystemColors::Control;
			grid[el]->BorderStyle=System::Windows::Forms::BorderStyle::FixedSingle;
			grid[el]->Click += grid_callback;
			System::String^ str=gcnew System::String("Cell (" + tag->get_column_index() + "," + tag->get_row_index() + ") in the current vector. Click on the cell to activate/deactivate it.");
			grid_toolTip->SetToolTip(grid[el], str);
			this->Controls->Add(grid[el]);
		}
		this->ResumeLayout(false);
	};

	template <class T, class U> System::Void Problem<T, U>::remove_grid()
	{
		this->SuspendLayout();
		if (grid)
		{
			for(int el=0; el<grid->Length; el++)
			{
				this->Controls->Remove(grid[el]);
				delete grid[el];
			}
			delete grid;
		}
		this->ResumeLayout(false);
	};

	template <class T, class U> System::Void Problem<T, U>::show_vector()
	{
		this->SuspendLayout();
		if (grid)
		{
			comment_textBox->Text=parent->get_comment();
			for(unsigned int el=0; el<parent->get_number_of_elements(); el++)
			{
				U val=parent->get_value(el);
				if (val>=0 && val<=1)
				{
					int a=static_cast<int>(val * System::Drawing::SystemColors::ControlDarkDark.A);
					int r=static_cast<int>(val * System::Drawing::SystemColors::ControlDarkDark.R);
					int g=static_cast<int>(val * System::Drawing::SystemColors::ControlDarkDark.G);
					int b=static_cast<int>(val * System::Drawing::SystemColors::ControlDarkDark.B);
					grid[el]->BackColor=System::Drawing::Color::FromArgb(a, r, g, b);
				}
			}
			this->Refresh();
		}
		this->ResumeLayout(false);
	};

	template <> System::Void Problem<bool, double>::set_file_filter()
	{
		load_openFileDialog->Filter="Text Files (*.txt)|*.txt";
		save_saveFileDialog->Filter="Text Files (*.txt)|*.txt";
	}
	
	template <> System::Void Problem<unsigned char, double>::set_file_filter()
	{
		load_openFileDialog->Filter="IDX1 Files (*.idx1)|*.idx1|IDX3 Files (*.idsx3)|*.idx3";
		save_saveFileDialog->Filter="IDX1 Files (*.idx1)|*.idx1|IDX3 Files (*.idsx3)|*.idx3";
	}

	// Explicit Instantiation

	template ref class Problem<bool, double>;
	template ref class Problem<unsigned char, double>;
}
